import observe from "./observe.js";
import Dep from "./Dep.js";
export default function defineReactive(data, key, val) {
  // 为每个属性key创建收集依赖的dep，但需要注意的是：
  // 一个数组中的基本数据类型的项是走不到这一步的，也就是说数组中的基本数据类型的项没有自己的dep
  const dep = new Dep();
  //   console.log("defineReactive创建了dep给", data, "的", key);
  if (arguments.length == 2) {
    val = data[key];
  }

  //子元素要进行observe，至此形成了递归调用。（多个函数循环调用）
  let childOb = observe(val); // 如果val是一个对象，执行observe后则val的Observer里也会有一个Dep
  // 对数据添加dep的结果如下：
  //   let data = {
  //     a: [1, 2, 3,__ob__: Observer {dep: Dep}] // a本身有一个dep,
  //     __ob__: Observer {dep: Dep}
  //   };

  Object.defineProperty(data, key, {
    //可枚举
    enumerable: true,
    //可以被配置，比如delete
    configurable: true,
    // 读取key时触发 getter
    get: function () {
      // console.log(`你试图访问${data}的${key}属性，它的值为：${val}`);
      //如果现在处于依赖收集阶段
      if (window.target) {
        dep.depend(); // 收集依赖
        // console.log(
        //   `你试图访问${data}的${key}属性，${key}属性本身的dep收集了一下`
        // );
        if (childOb) {
          //   console.log(
          //     `你试图访问${data}的${key}属性，${key}属性这个对象上的Observer的dep收集了一下`
          //   );
          // 如果key属性的值（即val）也是一个对象，则childOb === val.__ob__（也就是val的Observer实例）
          // 因为此时触发的是key的getter，所以此时的收集的依赖应是key的依赖
          // 那为什么还要为key属性值上的Observer实例里的dep添加依赖的原因呢？
          // 这主要是为了适配数组的情况，如果key的值是一个数组，那么当数组调用那“7个方法”改变了自身也即是改变了key时，肯定就需要触发key的依赖啊
          // 这个时候数组就只能通过自身Observer实例里的dep来触发依赖，见array.js中使用ob.dep.notify()触发依赖
          childOb.dep.depend();
        }
      }

      return val;
    },
    //更改key时触发 setter
    set: function (newVal) {
      // console.log(`你试图改变${data}的${key}属性，它的新值为：${newVal}`);
      if (val === newVal) {
        return;
      }
      val = newVal;
      // 新的值也要经过observe处理变成响应式的
      childOb = observe(newVal);
      //
      dep.notify(); // 通知依赖
    },
  });
}
